package com.bocloud.cmp.driver.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.enums.BocloudStatus;
import com.bocloud.cmp.entity.enums.NetworkType;
import com.bocloud.cmp.model.ClusterModel;
import com.bocloud.cmp.model.DataStoreModel;
import com.bocloud.cmp.model.HostModel;
import com.bocloud.cmp.model.ImageModel;
import com.bocloud.cmp.model.NetworkCardModel;
import com.bocloud.cmp.model.NetworkModel;
import com.bocloud.cmp.model.PortGroupModel;
import com.bocloud.cmp.model.ResourcePoolModel;
import com.bocloud.cmp.model.ServerModel;
import com.bocloud.cmp.model.SnapshotModel;
import com.bocloud.cmp.model.SwitchModel;
import com.bocloud.cmp.model.VDCModel;
import com.bocloud.cmp.model.VolumeModel;
import com.bocloud.common.enums.OSCategory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.vmware.vim25.ArrayOfHostDatastoreBrowserSearchResults;
import com.vmware.vim25.BoolPolicy;
import com.vmware.vim25.DVPortSetting;
import com.vmware.vim25.DVPortgroupConfigInfo;
import com.vmware.vim25.DVPortgroupPolicy;
import com.vmware.vim25.DVSConfigInfo;
import com.vmware.vim25.DVSContactInfo;
import com.vmware.vim25.DVSNameArrayUplinkPortPolicy;
import com.vmware.vim25.DVSSecurityPolicy;
import com.vmware.vim25.DVSTrafficShapingPolicy;
import com.vmware.vim25.DVSUplinkPortPolicy;
import com.vmware.vim25.DatastoreSummary;
import com.vmware.vim25.Description;
import com.vmware.vim25.DistributedVirtualSwitchHostMemberPnicBacking;
import com.vmware.vim25.DistributedVirtualSwitchHostMemberPnicSpec;
import com.vmware.vim25.DistributedVirtualSwitchPortConnection;
import com.vmware.vim25.FileInfo;
import com.vmware.vim25.FileQuery;
import com.vmware.vim25.FileQueryFlags;
import com.vmware.vim25.GuestInfo;
import com.vmware.vim25.GuestNicInfo;
import com.vmware.vim25.GuestStackInfo;
import com.vmware.vim25.HostDatastoreBrowserSearchResults;
import com.vmware.vim25.HostDatastoreBrowserSearchSpec;
import com.vmware.vim25.HostHardwareSummary;
import com.vmware.vim25.HostListSummary;
import com.vmware.vim25.HostNetworkConfig;
import com.vmware.vim25.HostNetworkInfo;
import com.vmware.vim25.HostNetworkPolicy;
import com.vmware.vim25.HostNetworkSecurityPolicy;
import com.vmware.vim25.HostNetworkTrafficShapingPolicy;
import com.vmware.vim25.HostNicFailureCriteria;
import com.vmware.vim25.HostNicOrderPolicy;
import com.vmware.vim25.HostNicTeamingPolicy;
import com.vmware.vim25.HostPortGroup;
import com.vmware.vim25.HostPortGroupConfig;
import com.vmware.vim25.HostPortGroupPort;
import com.vmware.vim25.HostPortGroupSpec;
import com.vmware.vim25.HostProxySwitch;
import com.vmware.vim25.HostSystemConnectionState;
import com.vmware.vim25.HostSystemPowerState;
import com.vmware.vim25.HostVirtualNic;
import com.vmware.vim25.HostVirtualSwitch;
import com.vmware.vim25.HostVirtualSwitchBondBridge;
import com.vmware.vim25.HostVirtualSwitchConfig;
import com.vmware.vim25.HostVirtualSwitchSpec;
import com.vmware.vim25.IsoImageFileInfo;
import com.vmware.vim25.IsoImageFileQuery;
import com.vmware.vim25.LinkDiscoveryProtocolConfig;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.NetDnsConfigInfo;
import com.vmware.vim25.NetIpConfigInfoIpAddress;
import com.vmware.vim25.NetIpRouteConfigInfo;
import com.vmware.vim25.NetIpRouteConfigInfoGateway;
import com.vmware.vim25.NetIpRouteConfigInfoIpRoute;
import com.vmware.vim25.NumericRange;
import com.vmware.vim25.PhysicalNic;
import com.vmware.vim25.ResourceAllocationInfo;
import com.vmware.vim25.ResourceConfigSpec;
import com.vmware.vim25.SharesInfo;
import com.vmware.vim25.VMwareDVSConfigInfo;
import com.vmware.vim25.VMwareDVSPortSetting;
import com.vmware.vim25.VMwareDVSPortgroupPolicy;
import com.vmware.vim25.VMwareDVSPvlanMapEntry;
import com.vmware.vim25.VMwareIpfixConfig;
import com.vmware.vim25.VMwareUplinkPortOrderPolicy;
import com.vmware.vim25.VirtualDevice;
import com.vmware.vim25.VirtualDeviceBackingInfo;
import com.vmware.vim25.VirtualDeviceDeviceBackingInfo;
import com.vmware.vim25.VirtualDisk;
import com.vmware.vim25.VirtualEthernetCard;
import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo;
import com.vmware.vim25.VirtualMachineConfigInfo;
import com.vmware.vim25.VirtualMachineConnectionState;
import com.vmware.vim25.VirtualMachineSnapshotTree;
import com.vmware.vim25.VirtualMachineSummary;
import com.vmware.vim25.VirtualMachineToolsStatus;
import com.vmware.vim25.VmwareDistributedVirtualSwitchPvlanSpec;
import com.vmware.vim25.VmwareDistributedVirtualSwitchTrunkVlanSpec;
import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec;
import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanSpec;
import com.vmware.vim25.VmwareUplinkPortTeamingPolicy;
import com.vmware.vim25.mo.ClusterComputeResource;
import com.vmware.vim25.mo.ComputeResource;
import com.vmware.vim25.mo.Datacenter;
import com.vmware.vim25.mo.Datastore;
import com.vmware.vim25.mo.DistributedVirtualPortgroup;
import com.vmware.vim25.mo.DistributedVirtualSwitch;
import com.vmware.vim25.mo.DistributedVirtualSwitchManager;
import com.vmware.vim25.mo.Folder;
import com.vmware.vim25.mo.HostNetworkSystem;
import com.vmware.vim25.mo.HostSystem;
import com.vmware.vim25.mo.InventoryNavigator;
import com.vmware.vim25.mo.ManagedEntity;
import com.vmware.vim25.mo.Network;
import com.vmware.vim25.mo.ResourcePool;
import com.vmware.vim25.mo.Task;
import com.vmware.vim25.mo.VirtualMachine;
import com.vmware.vim25.mo.VmwareDistributedVirtualSwitch;

/**
 * 组装对象工具类
 *
 * @author weiwei
 */
public class AssembleTools {

    private static Logger logger = LoggerFactory.getLogger(AssembleTools.class);

    public static AssembleTools getInstance() {
        return new AssembleTools();
    }

    /**
     * 迭代获取文件夹下的所有分布式交换机网络
     *
     * @param networks
     * @param switchers
     * @param folder
     * @throws Exception
     */
    private void getChildrenNetwork(List<NetworkModel> networks, List<SwitchModel> switchers, Folder folder)
            throws Exception {
        ManagedEntity[] entities = folder.getChildEntity();
        if (null != entities && entities.length > 0) {
            for (ManagedEntity entity : entities) {
                if (entity instanceof VmwareDistributedVirtualSwitch) {
                    List<PortGroupModel> groups = Lists.newArrayList();
                    Map<String, String> portMap = Maps.newHashMap();
                    VmwareDistributedVirtualSwitch vSwitch = (VmwareDistributedVirtualSwitch) entity;
                    ManagedObjectReference[] references = vSwitch.getConfig().getUplinkPortgroup();
                    if (null != references) {
                        for (ManagedObjectReference reference : references) {
                            DistributedVirtualPortgroup uplinkPort = new DistributedVirtualPortgroup(
                                    entity.getServerConnection(), reference);
                            PortGroupModel group = new PortGroupModel();
                            group.setType(NetworkType.PortGroupType.UPLINK.name());
                            group = assembleDvPortGroup(group, uplinkPort);
                            portMap.put(uplinkPort.getMOR().getVal(), uplinkPort.getName());
                            groups.add(group);
                        }
                    }
                    DistributedVirtualPortgroup[] portgroups = vSwitch.getPortgroup();
                    for (DistributedVirtualPortgroup portgroup : portgroups) {
                        if (portMap.containsKey(portgroup.getMOR().getVal())) {
                            continue;
                        }
                        PortGroupModel group = new PortGroupModel();
                        group.setType(NetworkType.PortGroupType.DVPORT.name());
                        group = assembleDvPortGroup(group, portgroup);
                        groups.add(group);
                    }
                    int portNum = vSwitch.getConfig().getNumPorts();
                    String val = vSwitch.getMOR().getVal();
                    String status = vSwitch.getOverallStatus().toString();
                    NetworkModel networkModel = new NetworkModel(vSwitch.getName(),
                            NetworkType.SwitchType.DVSWITCH.name(), status, portNum, val);
                    networks.add(networkModel);
                    SwitchModel switchModel = new SwitchModel();
                    switchModel = assembleDvSwitch(switchModel, vSwitch);
                    switchModel.setGroups(groups);
                    switchers.add(switchModel);
                } else if (entity instanceof Folder) {
                    Folder childFolder = (Folder) entity;
                    getChildrenNetwork(networks, switchers, childFolder);
                }
            }
        }
    }

    /**
     * 组装数据中心相关元数据
     *
     * @param managedEntity
     * @return
     * @throws Exception
     */
    public VDCModel assembleDc(ManagedEntity managedEntity) throws Exception {
        Datacenter datacenter = (Datacenter) managedEntity;
        List<NetworkModel> networks = Lists.newArrayList();
        List<SwitchModel> switchers = Lists.newArrayList();
        ManagedEntity[] entities = datacenter.getNetworkFolder().getChildEntity();
        logger.info("entities" + entities);
        for (ManagedEntity entity : entities) {
            if (entity instanceof Network && !(entity instanceof DistributedVirtualPortgroup)) {
            	logger.info("entity instanceof Network && !(entity instanceof DistributedVirtualPortgroup)");
                int portNum = -1;
                HostSystem[] hosts = ((Network) entity).getHosts();
                if (hosts.length > 0) {
                    int index = 0;
                    HostSystem host = null;
                    HostPortGroupConfig[] pgConfigs = null;
                    boolean flag = false;
                    while (true) {
                        if (hosts.length == index) {
                            break;
                        }
                        host = ((Network) entity).getHosts()[index];
                        if (null == host || null == host.getHostNetworkSystem()
                                || null == host.getHostNetworkSystem().getNetworkConfig()
                                || null == host.getHostNetworkSystem().getNetworkConfig().getPortgroup()) {
                            index++;
                            continue;
                        } else {
                            flag = true;
                            pgConfigs = host.getHostNetworkSystem().getNetworkConfig().getPortgroup();
                            break;
                        }
                    }
                    if (!flag) {
                        continue;
                    }
                    HostNetworkConfig networkConfig = host.getHostNetworkSystem().getNetworkConfig();
                    if (null != networkConfig) {
                        HostVirtualSwitchConfig[] vsConfigs = networkConfig.getVswitch();
                        for (HostPortGroupConfig pgConfig : pgConfigs) {
                            if (entity.getName().equals(pgConfig.getSpec().getName())) {
                                for (HostVirtualSwitchConfig vsConfig : vsConfigs) {
                                    if (pgConfig.getSpec().getVswitchName().equals(vsConfig.getName())) {
                                        portNum = vsConfig.getSpec().getNumPorts();
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
                if (portNum != -1 && portNum >= 8) {
                    NetworkModel networkModel = new NetworkModel(entity.getName(),
                            NetworkType.SwitchType.VSWITCH.name(), entity.getOverallStatus().toString(), portNum - 8,
                            entity.getMOR().getVal());
                    networks.add(networkModel);
                } else {
                    NetworkModel networkModel = new NetworkModel(entity.getName(),
                            NetworkType.SwitchType.VSWITCH.name(), entity.getOverallStatus().toString(), null,
                            entity.getMOR().getVal());
                    networks.add(networkModel);
                }
            } else if (entity instanceof VmwareDistributedVirtualSwitch) {
            	logger.info("ntity instanceof VmwareDistributedVirtualSwitch");
                List<PortGroupModel> groups = Lists.newArrayList();
                Map<String, String> portMap = Maps.newHashMap();
                VmwareDistributedVirtualSwitch vSwitch = (VmwareDistributedVirtualSwitch) entity;
                ManagedObjectReference[] references = vSwitch.getConfig().getUplinkPortgroup();
                if (null != references) {
                    for (ManagedObjectReference reference : references) {
                        DistributedVirtualPortgroup uplinkPort = new DistributedVirtualPortgroup(
                                entity.getServerConnection(), reference);
                        PortGroupModel group = new PortGroupModel();
                        group.setType(NetworkType.PortGroupType.UPLINK.name());
                        group = assembleDvPortGroup(group, uplinkPort);
                        portMap.put(uplinkPort.getMOR().getVal(), uplinkPort.getName());
                        groups.add(group);
                    }
                }
                DistributedVirtualPortgroup[] portgroups = vSwitch.getPortgroup();
                for (DistributedVirtualPortgroup portgroup : portgroups) {
                    if (portMap.containsKey(portgroup.getMOR().getVal())) {
                        continue;
                    }
                    PortGroupModel group = new PortGroupModel();
                    group.setType(NetworkType.PortGroupType.DVPORT.name());
                    group = assembleDvPortGroup(group, portgroup);
                    groups.add(group);
                }
                int portNum = vSwitch.getConfig().getNumPorts();
                String val = vSwitch.getMOR().getVal();
                String status = vSwitch.getOverallStatus().toString();
                NetworkModel networkModel = new NetworkModel(vSwitch.getName(), NetworkType.SwitchType.DVSWITCH.name(),
                        status, portNum, val);
                networks.add(networkModel);
                SwitchModel switchModel = new SwitchModel();
                switchModel = assembleDvSwitch(switchModel, vSwitch);
                switchModel.setGroups(groups);
                switchers.add(switchModel);
            } else if (entity instanceof Folder) {
            	logger.info("entity instanceof Folder");
                Folder childFolder = (Folder) entity;
                getChildrenNetwork(networks, switchers, childFolder);
            }
        }
        VDCModel vdc = new VDCModel(datacenter.getName(), 0l, 0l, 0D, 0l, 0l, 0D, null, null, null,
                datacenter.getMOR().getVal());
        List<ClusterModel> clusters = Lists.newArrayList();
        List<HostModel> hosts = Lists.newArrayList();
        List<DataStoreModel> stores = Lists.newArrayList();
        ManagedEntity[] hostEntities = datacenter.getHostFolder().getChildEntity();
        Datastore[] datastores = datacenter.getDatastores();
        logger.info("datastores" + datastores);
        if (null != datastores) {
            for (Datastore datastore : datastores) {
                DatastoreSummary datastoreSummary = datastore.getSummary();
                Long diskCapacity = datastoreSummary.getCapacity();
                Long freeCapacity = datastoreSummary.getFreeSpace();
                BigDecimal capacity = new BigDecimal(diskCapacity);
                BigDecimal freedisk = new BigDecimal(freeCapacity);
                Double diskTotal = capacity.divide(new BigDecimal(1024 * 1024 * 1024L), 2, RoundingMode.HALF_UP)
                        .doubleValue();
                Double diskFree = freedisk.divide(new BigDecimal(1024 * 1024 * 1024L), 2, RoundingMode.HALF_UP)
                        .doubleValue();
                // 获取存储下的虚拟机与模板
                int templateNum = 0;// 模板数量
                int vmNum = 0;// 虚拟机数量
                VirtualMachine[] vms = datastore.getVms();
                if (null != vms) {
                    for (VirtualMachine vm : vms) {
                        if (null != vm.getConfig()) {
                            if (vm.getConfig().isTemplate()) {
                                templateNum++;
                            } else {
                                vmNum++;
                            }
                        }
                    }
                }
                int hostNum = 0;
                if (null != datastore.getHost()) {
                    hostNum = datastore.getHost().length;
                }
                DataStoreModel dataStoreModel = new DataStoreModel(datastoreSummary.getName(),
                        datastoreSummary.getType(), datastoreSummary.getUrl(), diskTotal, diskFree, hostNum, vmNum,
                        templateNum, datastoreSummary.getDatastore().getVal());
                // 判断数据存储是否是活动状态
                if (!datastore.getSummary().accessible) {
                    dataStoreModel.setStatus("inactive");
                } else {
                    dataStoreModel.setStatus("green");
                }
                List<ImageModel> images = Lists.newArrayList();
                // 获取数据存储中的镜像文件
                HostDatastoreBrowserSearchSpec searchSpec = new HostDatastoreBrowserSearchSpec();
                FileQueryFlags flags = new FileQueryFlags();
                flags.setFileSize(true);
                flags.setModification(true);
                flags.setFileOwner(true);
                flags.setFileType(true);
                searchSpec.setDetails(flags);
                // 搜索不区分大小写
                searchSpec.setSearchCaseInsensitive(true);
                // 搜索之前是否先排序文件夹
                searchSpec.setSortFoldersFirst(true);
                // 查询.iso结尾的文件
                String[] matchPattern = new String[]{"*.iso"};
                searchSpec.setMatchPattern(matchPattern);
                IsoImageFileQuery isoQuery = new IsoImageFileQuery();
                FileQuery[] query = new FileQuery[]{isoQuery};
                searchSpec.setQuery(query);
                Task task = datastore.getBrowser().searchDatastoreSubFolders_Task("[" + datastore.getName() + "]",
                        searchSpec);
                if (task.waitForTask() == Task.SUCCESS) {
                    Object object = task.getTaskInfo().getResult();
                    if (object instanceof ArrayOfHostDatastoreBrowserSearchResults) {
                        ArrayOfHostDatastoreBrowserSearchResults searchResults = (ArrayOfHostDatastoreBrowserSearchResults) object;
                        HostDatastoreBrowserSearchResults[] results = searchResults
                                .getHostDatastoreBrowserSearchResults();
                        if (null != results && results.length > 0) {
                            for (HostDatastoreBrowserSearchResults result : results) {
                                FileInfo[] fileInfos = result.getFile();
                                if (null != fileInfos && fileInfos.length > 0) {
                                    for (FileInfo fileInfo : fileInfos) {
                                        if (fileInfo instanceof IsoImageFileInfo) {
                                            IsoImageFileInfo info = (IsoImageFileInfo) fileInfo;
                                            ImageModel imageModel = new ImageModel();
                                            String name = info.getPath();
                                            BigDecimal bigDecimal = new BigDecimal(0);
                                            if (null != info.getFileSize() && 0L != info.getFileSize()) {
                                                bigDecimal = new BigDecimal(info.getFileSize()).divide(
                                                        new BigDecimal(1024 * 1024 * 1024L), 2, RoundingMode.HALF_UP);
                                            }
                                            imageModel.setSize(bigDecimal.doubleValue());
                                            imageModel.setName(name);
                                            imageModel.setStatus("ACTIVE");
                                            imageModel.setOsType("ISO");
                                            imageModel.setStoreVal(datastore.getMOR().getVal());
                                            imageModel.setFilePath(result.getFolderPath() + info.getPath());
                                            images.add(imageModel);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                dataStoreModel.setImages(images);
                stores.add(dataStoreModel);
            }
        }
        logger.info("hostEntities" + hostEntities);
        if (null != hostEntities) {
            for (ManagedEntity hostEntity : hostEntities) {
                if (hostEntity instanceof ClusterComputeResource) {
                    ClusterComputeResource cluster = (ClusterComputeResource) hostEntity;
                    clusters.add(assembleCluster(cluster));
                } else if (hostEntity instanceof ComputeResource) {
                    ComputeResource hostSystem = (ComputeResource) hostEntity;
                    HostModel model = assembleVmwareHost(hostSystem.getHosts()[0]);
                    if (null != model) {
                        hosts.add(model);
                    }
                }
            }
        }
        // 组装资源池数据
        List<ResourcePoolModel> pools = Lists.newArrayList();
        ManagedEntity[] poolEntities = new InventoryNavigator(datacenter).searchManagedEntities("ResourcePool");
        logger.info("poolEntities" + poolEntities);
        for (ManagedEntity poolEntity : poolEntities) {
            ResourcePool resourcePool = (ResourcePool) poolEntity;
            if (resourcePool.getOwner() instanceof ClusterComputeResource) {
                ResourcePoolModel clusterPool = assembleVmwareResourcePool(resourcePool);
                ClusterComputeResource cluster = (ClusterComputeResource) resourcePool.getOwner();
                clusterPool.setVdcName(datacenter.getName());
                clusterPool.setClusterName(cluster.getName());
                clusterPool.setClusterVal(cluster.getMOR().getVal());
                clusterPool.setOwnerCategory(NetworkType.ResPoolOwnerType.CLUSTER.name());
                pools.add(clusterPool);
            } else if (resourcePool.getOwner() instanceof ComputeResource) {
                ResourcePoolModel hostPool = assembleVmwareResourcePool(resourcePool);
                ComputeResource host = (ComputeResource) resourcePool.getOwner();
                HostSystem hostSystem = host.getHosts()[0];
                hostPool.setVdcName(datacenter.getName());
                hostPool.setHostName(hostSystem.getName());
                hostPool.setHostVal(hostSystem.getMOR().getVal());
                hostPool.setOwnerCategory(NetworkType.ResPoolOwnerType.HOST.name());
                pools.add(hostPool);
            }
        }
        Long cpuTotal = 0l;
        Long memTotal = 0l;
        Double diskTotal = 0D;
        Long cpuUsed = 0l;
        Long memUsed = 0l;
        Double diskUsed = 0D;
        logger.info("clusters" + clusters);
        for (ClusterModel clusterModel : clusters) {
            cpuTotal += clusterModel.getCpuTotal();
            memTotal += clusterModel.getMemTotal();
            diskTotal += clusterModel.getDiskTotal();
            cpuUsed += clusterModel.getCpuUsed();
            memUsed += clusterModel.getMemUsed();
            diskUsed += clusterModel.getDiskUsed();
        }
        logger.info("hosts" + hosts);
        for (HostModel hostModel : hosts) {
            cpuTotal += hostModel.getCpuTotal();
            memTotal += hostModel.getMemTotal();
            diskTotal += hostModel.getDiskTotal();
            cpuUsed += hostModel.getCpuUsed();
            memUsed += hostModel.getMemUsed();
            diskUsed += hostModel.getDiskUsed();
        }
        vdc.setCpuTotal(cpuTotal);
        vdc.setDiskTotal(diskTotal);
        vdc.setMemTotal(memTotal);
        vdc.setCpuUsed(cpuUsed);
        vdc.setMemUsed(memUsed);
        vdc.setDiskUsed(diskUsed);
        vdc.setClusters(clusters);
        vdc.setHosts(hosts);
        vdc.setStores(stores);
        vdc.setNetworks(networks);
        vdc.setSwitchers(switchers);
        vdc.setPools(pools);
        return vdc;
    }

    /**
     * 组装标准交换机元数据
     *
     * @param model
     * @param vSwitch
     * @return
     */
    public SwitchModel assembleVswitch(SwitchModel model, HostVirtualSwitch vSwitch) {
        if (null == model) {
            model = new SwitchModel();
        }
        model.setName(vSwitch.getName());
        model.setType(NetworkType.SwitchType.VSWITCH.name());
        HostVirtualSwitchSpec spec = vSwitch.getSpec();
        if (null != spec) {
            model.setPortNum(Long.valueOf(spec.getNumPorts() - 8L));
            model.setSwitcherVal(vSwitch.getKey());
            model.setMtu(spec.getMtu());
            HostNetworkPolicy policy = spec.getPolicy();
            if (null != policy) {
                HostNetworkSecurityPolicy security = policy.getSecurity();
                if (null != security) {
                    model.setAllowPromiscuous(security.getAllowPromiscuous());
                    model.setMacChanges(security.getMacChanges());
                    model.setForgedTransmits(security.getForgedTransmits());
                }
                HostNetworkTrafficShapingPolicy shapingPolicy = policy.getShapingPolicy();
                if (null != shapingPolicy) {
                    model.setTrafficEnabled(shapingPolicy.getEnabled());
                    model.setAverageBandWidth(shapingPolicy.getAverageBandwidth());
                    model.setPeakBandWidth(shapingPolicy.getPeakBandwidth());
                    model.setBurstSize(shapingPolicy.getBurstSize());
                }
                HostNicTeamingPolicy nicTeaming = policy.getNicTeaming();
                if (null != nicTeaming) {
                    model.setPolicy(nicTeaming.getPolicy());
                    HostNicFailureCriteria failureCriteria = nicTeaming.getFailureCriteria();
                    if (null != failureCriteria) {
                        model.setCheckBeacon(failureCriteria.getCheckBeacon());
                    } else {
                        model.setCheckBeacon(false);
                    }
                    model.setNotifySwitches(nicTeaming.getNotifySwitches());
                    model.setRollingOrder(nicTeaming.getRollingOrder());
                    HostNicOrderPolicy nicOrder = nicTeaming.getNicOrder();
                    if (null != nicOrder) {
                        String[] activeNics = nicOrder.getActiveNic();
                        if (null != activeNics && activeNics.length > 0) {
                            model.setActiveNics(Arrays.asList(activeNics));
                        }
                        String[] standbyNics = nicOrder.getStandbyNic();
                        if (null != standbyNics && standbyNics.length > 0) {
                            model.setStandbyNics(Arrays.asList(standbyNics));
                        }
                    }
                }
            }
        }
        return model;
    }

    /**
     * 组装分布式交换机元数据
     *
     * @param model
     * @param dvSwitch
     * @return
     */
    public SwitchModel assembleDvSwitch(SwitchModel model, DistributedVirtualSwitch dvSwitch) {
        if (null == model) {
            model = new SwitchModel();
        }
        model.setName(dvSwitch.getName());
        model.setStatus(dvSwitch.getOverallStatus().toString());
        model.setType(NetworkType.SwitchType.DVSWITCH.name());
        model.setSwitcherVal(dvSwitch.getMOR().getVal());
        DVSConfigInfo configInfo = dvSwitch.getConfig();
        if (null != configInfo && configInfo instanceof VMwareDVSConfigInfo) {
            VMwareDVSConfigInfo config = (VMwareDVSConfigInfo) configInfo;
            VMwareDVSPvlanMapEntry[] pvlanConfig = config.getPvlanConfig();
            if (null != pvlanConfig && pvlanConfig.length > 0) {
                model.setpVlans(JSONObject.toJSONString(pvlanConfig));
            }
            model.setPortNum(Long.valueOf(config.getNumPorts()));
            model.setMtu(config.getMaxMtu());
            model.setRemark(config.getDescription());
            DVPortSetting portSetting = config.getDefaultPortConfig();
            if (null != portSetting && portSetting instanceof VMwareDVSPortSetting) {
                VMwareDVSPortSetting setting = (VMwareDVSPortSetting) portSetting;
                DVSSecurityPolicy securityPolicy = setting.getSecurityPolicy();
                if (null != securityPolicy) {
                    model.setAllowPromiscuous(securityPolicy.getAllowPromiscuous().getValue());
                    model.setMacChanges(securityPolicy.getMacChanges().getValue());
                    model.setForgedTransmits(securityPolicy.getForgedTransmits().getValue());
                }
            }
            DVSContactInfo contact = config.getContact();
            if (null != contact) {
                model.setManagerName(contact.getName());
                model.setManagerContact(contact.getContact());
            }
            LinkDiscoveryProtocolConfig linkDiscoveryProtocolConfig = config.getLinkDiscoveryProtocolConfig();
            if (null != linkDiscoveryProtocolConfig) {
                model.setProtocol(linkDiscoveryProtocolConfig.getProtocol());
                model.setOperation(linkDiscoveryProtocolConfig.getOperation());
            }
            DVSUplinkPortPolicy uplinkPortPolicy = config.getUplinkPortPolicy();
            if (null != uplinkPortPolicy && uplinkPortPolicy instanceof DVSNameArrayUplinkPortPolicy) {
                DVSNameArrayUplinkPortPolicy portPolicy = (DVSNameArrayUplinkPortPolicy) uplinkPortPolicy;
                String[] uplinkPortName = portPolicy.getUplinkPortName();
                if (null != uplinkPortName && uplinkPortName.length > 0) {
                    model.setDvportNum(portPolicy.getUplinkPortName().length);
                    model.setDvportNames(Arrays.asList(portPolicy.getUplinkPortName()));
                }
            }
            VMwareIpfixConfig ipfixConfig = config.getIpfixConfig();
            if (null != ipfixConfig) {
                model.setCollectorIpAddress(ipfixConfig.getCollectorIpAddress());
                model.setCollectorPort(ipfixConfig.getCollectorPort());
                model.setActiveFlowTimeout(ipfixConfig.getActiveFlowTimeout());
                model.setIdleFlowTimeout(ipfixConfig.getIdleFlowTimeout());
                model.setSamplingRate(ipfixConfig.getSamplingRate());
                model.setInternalFlowsOnly(ipfixConfig.isInternalFlowsOnly());
            }
            model.setVdsIpAddress(config.getSwitchIpAddress());
        }
        return model;
    }

    /**
     * 组装分布式端口组或上行链路端口组相关元数据
     *
     * @param groupModel
     * @param group
     * @return
     */
    public PortGroupModel assembleDvPortGroup(PortGroupModel groupModel, DistributedVirtualPortgroup group) {
        if (null == groupModel) {
            groupModel = new PortGroupModel();
        }
        DVPortgroupConfigInfo config = group.getConfig();
        groupModel.setName(group.getName());
        groupModel.setGroupVal(group.getMOR().getVal());
        if (null != config) {
            groupModel.setPortNum(config.getNumPorts());
            groupModel.setRemark(config.getDescription());
            DVPortSetting dvPortSetting = config.getDefaultPortConfig();
            if (null != dvPortSetting && dvPortSetting instanceof VMwareDVSPortSetting) {
                VMwareDVSPortSetting defaultPortConfig = (VMwareDVSPortSetting) dvPortSetting;
                DVSSecurityPolicy securityPolicy = defaultPortConfig.getSecurityPolicy();
                if (null != securityPolicy) {
                    groupModel.setAllowPromiscuous(securityPolicy.getAllowPromiscuous().getValue());
                    groupModel.setMacChanges(securityPolicy.getMacChanges().getValue());
                    groupModel.setForgedTransmits(securityPolicy.getForgedTransmits().getValue());
                }
                DVSTrafficShapingPolicy inShapingPolicy = defaultPortConfig.getInShapingPolicy();
                if (null != inShapingPolicy) {
                    groupModel.setInTrafficEnabled(inShapingPolicy.getEnabled().getValue());
                    groupModel.setInAverageBandWidth(inShapingPolicy.getAverageBandwidth().getValue());
                    groupModel.setInPeakBandWidth(inShapingPolicy.getPeakBandwidth().getValue());
                    groupModel.setInBurstSize(inShapingPolicy.getBurstSize().getValue());
                }
                DVSTrafficShapingPolicy outShapingPolicy = defaultPortConfig.getOutShapingPolicy();
                if (null != outShapingPolicy) {
                    groupModel.setOutTrafficEnabled(outShapingPolicy.getEnabled().getValue());
                    groupModel.setOutAverageBandWidth(outShapingPolicy.getAverageBandwidth().getValue());
                    groupModel.setOutPeakBandWidth(outShapingPolicy.getPeakBandwidth().getValue());
                    groupModel.setOutBurstSize(outShapingPolicy.getBurstSize().getValue());
                }
                VmwareUplinkPortTeamingPolicy uplinkTeamingPolicy = defaultPortConfig.getUplinkTeamingPolicy();
                if (null != uplinkTeamingPolicy) {
                    groupModel.setPolicy(uplinkTeamingPolicy.getPolicy().getValue());
                    BoolPolicy checkBeacon = uplinkTeamingPolicy.getFailureCriteria().getCheckBeacon();
                    if (null != checkBeacon) {
                        groupModel.setCheckBeacon(checkBeacon.getValue());
                    } else {
                        groupModel.setCheckBeacon(false);
                    }
                    groupModel.setNotifySwitches(uplinkTeamingPolicy.getNotifySwitches().getValue());
                    groupModel.setRollingOrder(uplinkTeamingPolicy.getRollingOrder().getValue());
                    VMwareUplinkPortOrderPolicy uplinkPortOrder = uplinkTeamingPolicy.getUplinkPortOrder();
                    if (null != uplinkPortOrder) {
                        String[] activeUplinkPort = uplinkPortOrder.getActiveUplinkPort();
                        if (null != activeUplinkPort && activeUplinkPort.length > 0) {
                            groupModel.setActiveUplinks(Arrays.asList(activeUplinkPort));
                        }
                        String[] standbyUplinkPort = uplinkPortOrder.getStandbyUplinkPort();
                        if (null != standbyUplinkPort && standbyUplinkPort.length > 0) {
                            groupModel.setStandbyUplinks(Arrays.asList(standbyUplinkPort));
                        }
                    }
                    groupModel.setIpfixEnabled(defaultPortConfig.getIpfixEnabled().getValue());
                    DVPortgroupPolicy policy = config.getPolicy();
                    if (null != policy && policy instanceof VMwareDVSPortgroupPolicy) {
                        VMwareDVSPortgroupPolicy groupPolicy = (VMwareDVSPortgroupPolicy) policy;
                        groupModel.setDisconnectConfigReset(groupPolicy.isPortConfigResetAtDisconnect());
                        groupModel.setAllowOverridePolicy(groupPolicy.isUplinkTeamingOverrideAllowed());
                    } else {
                        groupModel.setDisconnectConfigReset(true);
                        groupModel.setAllowOverridePolicy(true);
                    }
                    VmwareDistributedVirtualSwitchVlanSpec vlan = defaultPortConfig.getVlan();
                    if (null != vlan) {
                        if (vlan instanceof VmwareDistributedVirtualSwitchVlanIdSpec) {
                            VmwareDistributedVirtualSwitchVlanIdSpec vlanSpec = (VmwareDistributedVirtualSwitchVlanIdSpec) vlan;
                            groupModel.setVlanType(NetworkType.VlanType.Vlan.name());
                            groupModel.setVlanId(vlanSpec.getVlanId());
                        } else if (vlan instanceof VmwareDistributedVirtualSwitchTrunkVlanSpec) {
                            VmwareDistributedVirtualSwitchTrunkVlanSpec trunkVlanSpec = (VmwareDistributedVirtualSwitchTrunkVlanSpec) vlan;
                            NumericRange[] vlanId = trunkVlanSpec.getVlanId();
                            groupModel.setVlanType(NetworkType.VlanType.TrunkVlan.name());
                            if (null != vlanId && vlanId.length > 0) {
                                groupModel.setTrunkVlan(JSONObject.toJSONString(vlanId));
                            }
                        } else if (vlan instanceof VmwareDistributedVirtualSwitchPvlanSpec) {
                            VmwareDistributedVirtualSwitchPvlanSpec pVlanSpec = (VmwareDistributedVirtualSwitchPvlanSpec) vlan;
                            groupModel.setVlanType(NetworkType.VlanType.Pvlan.name());
                            groupModel.setVlanId(pVlanSpec.getPvlanId());
                        }
                    }
                }
                BoolPolicy blocked = defaultPortConfig.getBlocked();
                if (null != blocked) {
                    groupModel.setBlocked(defaultPortConfig.getBlocked().getValue());
                } else {
                    groupModel.setBlocked(false);
                }
            }
        }
        return groupModel;
    }

    /**
     * 组装虚拟机端口组或VMKernel相关元数据
     *
     * @param groupModel
     * @param group
     * @return
     */
    public PortGroupModel assemblePortGroup(PortGroupModel groupModel, HostPortGroup group) {
        if (null == groupModel) {
            groupModel = new PortGroupModel();
        }
        HostPortGroupSpec groupSpec = group.getSpec();
        HostPortGroupPort[] ports = group.getPort();
        if (null != ports && ports.length > 0) {
            groupModel.setPortNum(ports.length);
        } else {
            groupModel.setPortNum(0);
        }
        if (null != groupSpec) {
            groupModel.setName(groupSpec.getName());
            groupModel.setVlanType(NetworkType.VlanType.Vlan.name());
            groupModel.setVlanId(groupSpec.getVlanId());
            HostNetworkPolicy networkPolicy = groupSpec.getPolicy();
            if (null != networkPolicy) {
                HostNetworkSecurityPolicy security = networkPolicy.getSecurity();
                HostNetworkTrafficShapingPolicy shapingPolicy = networkPolicy.getShapingPolicy();
                HostNicTeamingPolicy nicTeaming = networkPolicy.getNicTeaming();
                if (null != security) {
                    groupModel.setAllowPromiscuous(security.getAllowPromiscuous());
                    groupModel.setMacChanges(security.getMacChanges());
                    groupModel.setForgedTransmits(security.getForgedTransmits());
                }
                if (null != shapingPolicy) {
                    groupModel.setInTrafficEnabled(shapingPolicy.getEnabled());
                    groupModel.setInAverageBandWidth(shapingPolicy.getAverageBandwidth());
                    groupModel.setInPeakBandWidth(shapingPolicy.getPeakBandwidth());
                    groupModel.setInBurstSize(shapingPolicy.getBurstSize());
                }
                if (null != nicTeaming) {
                    HostNicFailureCriteria failureCriteria = nicTeaming.getFailureCriteria();
                    if (null != failureCriteria) {
                        groupModel.setCheckBeacon(failureCriteria.getCheckBeacon());
                    }
                    groupModel.setPolicy(nicTeaming.getPolicy());
                    groupModel.setNotifySwitches(nicTeaming.getNotifySwitches());
                    groupModel.setRollingOrder(nicTeaming.getRollingOrder());
                    HostNicOrderPolicy orderPolicy = nicTeaming.getNicOrder();
                    if (null != orderPolicy) {
                        String[] activeNics = orderPolicy.getActiveNic();
                        if (null != activeNics && activeNics.length > 0) {
                            groupModel.setActiveNics(Arrays.asList(activeNics));
                        }
                        String[] standbyNics = orderPolicy.getStandbyNic();
                        if (null != standbyNics && standbyNics.length > 0) {
                            groupModel.setStandbyNics(Arrays.asList(standbyNics));
                        }
                    }
                }
            }
        }
        return groupModel;
    }

    /**
     * 组装资源池相关元数据
     *
     * @param resourcePool
     * @return
     * @throws Exception
     */
    public ResourcePoolModel assembleVmwareResourcePool(ResourcePool resourcePool) throws Exception {
        ResourcePoolModel poolModel = new ResourcePoolModel();
        ManagedEntity parent = resourcePool.getParent();
        ManagedEntity owner = resourcePool.getOwner();
        ResourceConfigSpec spec = resourcePool.getConfig();
        if (null != spec) {
            // 集群或宿主机本身资源池的父资源池名和所属对象名称相同
            if (parent.getName().equals(owner.getName())) {
                poolModel.setName(resourcePool.getName());
            } else {
                poolModel.setParentName(parent.getName());
                poolModel.setParentPoolVal(parent.getMOR().getVal());
                poolModel.setName(resourcePool.getName());
            }
            Calendar modified = spec.getLastModified();
            if (null != modified) {
                poolModel.setGmtModify(modified.getTime());
            }
            ResourceAllocationInfo cpuInfo = spec.getCpuAllocation();
            if (null != cpuInfo) {
                poolModel.setCpuReservation(cpuInfo.getReservation());
                poolModel.setCpuExpanReservation(cpuInfo.getExpandableReservation());
                poolModel.setCpuLimit(cpuInfo.getLimit());
                SharesInfo cpuShares = cpuInfo.getShares();
                if (null != cpuShares) {
                    poolModel.setCpuShareLevel(cpuShares.getLevel().name());
                    poolModel.setCpuShares(cpuShares.getShares());
                }
            }
            ResourceAllocationInfo memInfo = spec.getMemoryAllocation();
            if (null != memInfo) {
                poolModel.setMemReservation(memInfo.getReservation());
                poolModel.setMemExpanReservation(memInfo.getExpandableReservation());
                poolModel.setMemLimit(memInfo.getLimit());
                SharesInfo memShares = memInfo.getShares();
                if (null != memShares) {
                    poolModel.setMemShareLevel(memShares.getLevel().name());
                    poolModel.setMemShares(memShares.getShares());
                }
            }
        }
        poolModel.setPoolVal(resourcePool.getMOR().getVal());
        return poolModel;
    }

    /**
     * 组装主机集群相关元数据
     *
     * @param entity
     * @return
     * @throws Exception
     */
    public ClusterModel assembleCluster(ClusterComputeResource entity) throws Exception {
        ClusterModel cluster = new ClusterModel();
        cluster.setName(entity.getName());
        cluster.setClusterVal(entity.getMOR().getVal());
        HostSystem[] hostSystems = entity.getHosts();
        List<HostModel> hosts = Lists.newArrayList();
        int templateNum = 0;// 模板数量
        int vmNum = 0;// 虚拟机数量
        // 遍历集群中hostSystem，判断所有的hostSystem下一共有多少虚拟机，即该集群下一共有多少虚拟机
        if (null != hostSystems) {
            for (HostSystem hostSystem : hostSystems) {
                VirtualMachine[] vmArray = hostSystem.getVms();// 某一个hostSystem下所有的虚拟机（取出的数量=虚拟机+模板）
                for (VirtualMachine virtualMachine : vmArray) {
                    if (null == virtualMachine.getConfig()) {
                        continue;
                    }
                    if (virtualMachine.getConfig().isTemplate()) {
                        templateNum++;
                    } else {
                        vmNum++;
                    }
                }
                HostModel model = assembleVmwareHost(hostSystem);
                if (null != model) {
                    hosts.add(model);
                }
            }
        }

        cluster.setHosts(hosts);
        cluster.setTemplateNum(templateNum);
        cluster.setVmNum(vmNum);
        // 集群中宿主机（物理机）数量
        if (null != hostSystems) {
            cluster.setHostNum(hostSystems.length);
        } else {
            cluster.setHostNum(0);
        }

        Long cpuTotal = 0l;
        Long memTotal = 0l;
        Double diskTotal = 0D;
        Long cpuUsed = 0l;
        Long memUsed = 0l;
        Double diskUsed = 0D;
        int cpuCore = 0;
        for (HostModel hostModel : hosts) {
            cpuTotal += hostModel.getCpuTotal();
            memTotal += hostModel.getMemTotal();
            diskTotal += hostModel.getDiskTotal();
            cpuUsed += hostModel.getCpuUsed();
            memUsed += hostModel.getMemUsed();
            diskUsed += hostModel.getDiskUsed();
            cpuCore += hostModel.getCpuCore();
        }
        cluster.setCpuTotal(cpuTotal);
        cluster.setMemTotal(memTotal);
        cluster.setDiskTotal(diskTotal);
        cluster.setCpuUsed(cpuUsed);
        cluster.setMemUsed(memUsed);
        cluster.setDiskUsed(diskUsed);
        cluster.setCpuCore(cpuCore);
        return cluster;
    }

    public HostModel assembleVmwareHost(HostSystem host) throws Exception {
        HostModel hostModel = new HostModel();
        ResourcePool resourcePool = null;
        ManagedEntity[] entities = new InventoryNavigator(host.getParent().getParent().getParent())
                .searchManagedEntities("ResourcePool");
        if (null != entities && entities.length > 0) {
            for (ManagedEntity managedEntity : entities) {
                ResourcePool pool = (ResourcePool) managedEntity;
                if (pool.getOwner().getName().equals(host.getName())) {
                    resourcePool = pool;
                    break;
                }
            }
        }
        if (null != resourcePool) {
            hostModel.setResourcePool(assembleVmwareResourcePool(resourcePool));
        }
        List<ServerModel> serverModels = new ArrayList<>();
        HostListSummary summary = host.getSummary();
        if (null == summary) {
            return null;
        }
        HostHardwareSummary hardware = summary.getHardware();
        if (null == hardware) {
            return null;
        }
        hostModel.setName(host.getName());
        hostModel.setUuid(hardware.getUuid());
        hostModel.setVendor(hardware.getVendor());
        if (null != host.getConfig() && null != host.getConfig().getProduct()) {
            hostModel.setCatalog(host.getConfig().getProduct().getName());
        }
        hostModel.setCategory(hardware.getModel());
        hostModel.setCpuModel(hardware.getCpuModel());
        hostModel.setCpuNum((int) hardware.getNumCpuPkgs());
        hostModel.setCpuCore((int) hardware.getNumCpuCores());
        hostModel.setCpuTotal(Long.valueOf(hardware.getCpuMhz()) * hardware.getNumCpuCores());
        hostModel.setMaintained(summary.getRuntime().isInMaintenanceMode());// 物理机是否处于维护模式
        HostSystemConnectionState connState = summary.getRuntime().getConnectionState();// 物理机连接状态
        if (connState.equals(HostSystemConnectionState.connected)) {
            hostModel.setConnected(true);
            hostModel.setCpuUsed(summary.getQuickStats().getOverallCpuUsage().longValue());
            hostModel.setMemUsed(summary.getQuickStats().getOverallMemoryUsage().longValue());
        } else {
            hostModel.setConnected(false);
            hostModel.setCpuUsed(0L);
            hostModel.setMemUsed(0L);
        }
        // 获取宿主机（物理机的IP）
        if (null != host.getHostNetworkSystem().getNetworkInfo()) {
            HostVirtualNic[] virtualNicArray = host.getHostNetworkSystem().getNetworkInfo().getVnic();// 获取虚拟网卡
            if (null != virtualNicArray) {
                for (HostVirtualNic hostVirtualNic : virtualNicArray) {
                    String hostIp = hostVirtualNic.getSpec().getIp().getIpAddress();// 获取物理机的ip
                    if (!StringUtils.isEmpty(hostIp)) {
                        hostModel.setHostIp(hostIp);
                        break;
                    }
                }
            }
        }
        BigDecimal memory = new BigDecimal(hardware.getMemorySize());
        hostModel.setMemTotal(memory.divide(new BigDecimal(1024 * 1024L), 1, RoundingMode.HALF_UP).longValue());
        List<String> stores = Lists.newArrayList();
        Datastore[] datastores = host.getDatastores();
        Long diskCapacity = 0l;
        Long freeCapacity = 0l;
        if (null != datastores) {
            List<DataStoreModel> models = Lists.newArrayList();
            for (Datastore datastore : datastores) {
                DatastoreSummary datastoreSummary = datastore.getSummary();
                stores.add(datastoreSummary.getDatastore().getVal());
                diskCapacity += datastoreSummary.getCapacity();
                freeCapacity += datastoreSummary.getFreeSpace();

                Long disk = datastoreSummary.getCapacity();
                Long free = datastoreSummary.getFreeSpace();
                BigDecimal capacity = new BigDecimal(disk);
                BigDecimal freedisk = new BigDecimal(free);
                Double diskTotal = capacity.divide(new BigDecimal(1024 * 1024 * 1024L), 2, RoundingMode.HALF_UP)
                        .doubleValue();
                Double diskFree = freedisk.divide(new BigDecimal(1024 * 1024 * 1024L), 2, RoundingMode.HALF_UP)
                        .doubleValue();
                // 获取存储下的虚拟机与模板
                int templateNum = 0;// 模板数量
                int vmNum = 0;// 虚拟机数量
                VirtualMachine[] vms = datastore.getVms();
                if (null != vms) {
                    for (VirtualMachine vm : vms) {
                        if (null != vm.getConfig()) {
                            if (vm.getConfig().isTemplate()) {
                                templateNum++;
                            } else {
                                vmNum++;
                            }
                        }
                    }
                }
                int hostNum = 0;
                if (null != datastore.getHost()) {
                    hostNum = datastore.getHost().length;
                }
                DataStoreModel dataStoreModel = new DataStoreModel(datastoreSummary.getName(),
                        datastoreSummary.getType(), datastoreSummary.getUrl(), diskTotal, diskFree, hostNum, vmNum,
                        templateNum, datastoreSummary.getDatastore().getVal());
                dataStoreModel.setStatus(datastore.getOverallStatus().toString());
                models.add(dataStoreModel);
            }
            hostModel.setDataStores(models);
            hostModel.setDatastoreNum(datastores.length);
        } else {
            hostModel.setDatastoreNum(0);
        }
        BigDecimal capacity = new BigDecimal(diskCapacity);
        BigDecimal freedisk = new BigDecimal(freeCapacity);
        Double diskTotal = capacity.divide(new BigDecimal(1024 * 1024 * 1024L), 2, RoundingMode.HALF_UP).doubleValue();
        Double diskFree = freedisk.divide(new BigDecimal(1024 * 1024 * 1024L), 2, RoundingMode.HALF_UP).doubleValue();
        hostModel.setStores(stores);
        hostModel.setDiskTotal(diskTotal);
        hostModel.setDiskUsed(diskTotal - diskFree);
        // 获取网络
        List<NetworkModel> nets = Lists.newArrayList();
        List<String> netNames = Lists.newArrayList();
        Map<String, NetworkModel> networkMap = Maps.newHashMap();
        Network[] networks = host.getNetworks();
        if (null != networks && networks.length > 0) {
            // 如果宿主机下连接了分布式交换机网络，则此处取到的network是分布式端口组
            for (Network network : networks) {
                NetworkModel model = null;
                if (network instanceof DistributedVirtualPortgroup) {
                    DistributedVirtualPortgroup portgroup = (DistributedVirtualPortgroup) network;
                    ManagedObjectReference distributedVirtualSwitch = portgroup.getConfig()
                            .getDistributedVirtualSwitch();
                    if (null != distributedVirtualSwitch) {
                        DistributedVirtualSwitch dvSwitch = new DistributedVirtualSwitch(host.getServerConnection(),
                                distributedVirtualSwitch);
                        if (!networkMap.containsKey(dvSwitch.getMOR().getVal())) {
                            model = new NetworkModel(dvSwitch.getName(), NetworkType.SwitchType.DVSWITCH.name(),
                                    dvSwitch.getOverallStatus().toString(), dvSwitch.getConfig().getNumPorts(),
                                    dvSwitch.getMOR().getVal());
                            networkMap.put(dvSwitch.getMOR().getVal(), model);
                        }
                    }
                } else {
                    if (!networkMap.containsKey(network.getMOR().getVal())) {
                        model = new NetworkModel(network.getName(), NetworkType.SwitchType.VSWITCH.name(),
                                network.getOverallStatus().name(), null, network.getMOR().getVal());
                        networkMap.put(network.getMOR().getVal(), model);
                    }
                }
            }
        }
        for (NetworkModel model : networkMap.values()) {
            nets.add(model);
            netNames.add(model.getName());
        }
        hostModel.setNetworks(nets);
        // 获取主机标准交换机
        List<SwitchModel> switchers = Lists.newArrayList();
        HostNetworkSystem hostNetworkSystem = host.getHostNetworkSystem();
        if (null != hostNetworkSystem) {
            HostNetworkInfo networkInfo = hostNetworkSystem.getNetworkInfo();
            if (null != networkInfo) {
                HostVirtualSwitch[] vSwitchs = networkInfo.getVswitch();
                if (null != vSwitchs && vSwitchs.length > 0) {
                    for (HostVirtualSwitch vSwitch : vSwitchs) {
                        // 获取主机上的所有端口
                        HostPortGroup[] portGroups = networkInfo.getPortgroup();
                        if (null == portGroups) {
                            break;
                        }
                        List<PortGroupModel> groups = Lists.newArrayList();
                        for (HostPortGroup portGroup : portGroups) {
                            if (!portGroup.getSpec().getVswitchName().equals(vSwitch.getName())) {
                                continue;
                            }
                            String type = NetworkType.PortGroupType.VMKERNEL.name();
                            if (netNames.contains(portGroup.getSpec().getName())) {
                                type = NetworkType.PortGroupType.VIRTUAL.name();
                            }
                            PortGroupModel groupModel = new PortGroupModel();
                            groupModel.setType(type);
                            groupModel = assemblePortGroup(groupModel, portGroup);
                            groups.add(groupModel);
                        }
                        SwitchModel model = new SwitchModel();
                        model = assembleVswitch(model, vSwitch);
                        model.setGroups(groups);
                        switchers.add(model);
                    }
                }
            }
        }
        hostModel.setSwitchers(switchers);
        // 获取宿主机下的所有虚拟机
        VirtualMachine[] machines = host.getVms();// 某一个hostSystem下所有的虚拟机（取出的数量=虚拟机+模板）
        int templateNum = 0;// 物理机下模板数量
        int vmNum = 0;// 物理机下虚拟机下数量
        if (null != machines) {
            for (VirtualMachine machine : machines) {
                ServerModel serverModel = convertServer(machine);
                if (null != serverModel) {
                    if (serverModel.getIsTemplate()) {
                        templateNum++;
                    } else {
                        vmNum++;
                    }
                    serverModels.add(serverModel);
                }
            }
        }

        // 获取宿主机的电源状态
        HostSystemPowerState hostSystemPowerState = host.getRuntime().getPowerState();
        String hostPowerState = "STOPPED";
        if (hostSystemPowerState.equals(HostSystemPowerState.poweredOn)) {
            hostPowerState = "RUNNING";
        } else if (hostSystemPowerState.equals(HostSystemPowerState.poweredOff)) {
            hostPowerState = "STOPPED";
            hostModel.setConnected(false);
        } else if (hostSystemPowerState.equals(HostSystemPowerState.unknown)) {
            if (host.getRuntime().getConnectionState().equals(HostSystemConnectionState.notResponding)) {
                hostPowerState = "STOPPED";
            } else {
                hostPowerState = "UNKNOWN";
            }
            hostModel.setConnected(false);
        }

        // 获取特定物理机下已被使用的物理网卡（同一物理机下网卡的名称不重复
        Map<String, String> adapterMap = Maps.newHashMap();
        this.getAdapter(host, adapterMap);
        // 获取机器下的所有的所有的物理网卡
        List<NetworkCardModel> networkModels = Lists.newArrayList();
        HostNetworkInfo networkInfo = host.getConfig().getNetwork();
        if (null != networkInfo) {
            PhysicalNic[] pNics = networkInfo.getPnic();
            if (null != pNics && pNics.length > 0) {
                for (PhysicalNic physicalNic : pNics) {
                    NetworkCardModel networkCardModel = new NetworkCardModel();
                    if (adapterMap.containsKey(physicalNic.getDevice())) {
                        networkCardModel.setUsed(true);
                        networkCardModel.setSwitcher(adapterMap.get(physicalNic.getDevice()));
                    } else {
                        networkCardModel.setUsed(false);
                    }
                    networkCardModel.setName(physicalNic.getDevice());
                    networkCardModel.setMac(physicalNic.getMac());
                    networkModels.add(networkCardModel);
                }
            }
        }
        hostModel.setNetcards(networkModels);
        hostModel.setVmNum(vmNum);// 宿主机（物理机）包含的虚拟机数量
        hostModel.setPowerState(hostPowerState);// 宿主机电源状态
        hostModel.setTemplateNum(templateNum);
        hostModel.setServers(serverModels);
        hostModel.setStatus(hostPowerState);
        return hostModel;
    }

    /**
     * 获取物理机上已被使用的物理网卡
     *
     * @param ho
     * @param adapterMap
     * @throws Exception
     */
    private void getAdapter(HostSystem hostSystem, Map<String, String> adapterMap) throws Exception {
        HostNetworkSystem hostNetworkSystem = hostSystem.getHostNetworkSystem();
        if (null != hostNetworkSystem) {
            HostNetworkConfig networkConfig = hostNetworkSystem.getNetworkConfig();
            if (null != networkConfig) {
                // 标准交换机上被用的物理网卡
                HostVirtualSwitchConfig[] vsConfigs = networkConfig.getVswitch();
                if (null != vsConfigs && vsConfigs.length > 0) {
                    for (HostVirtualSwitchConfig vsConfig : vsConfigs) {
                        HostVirtualSwitchBondBridge bridge = (HostVirtualSwitchBondBridge) vsConfig.getSpec()
                                .getBridge();
                        if (null != bridge) {
                            String[] nics = bridge.getNicDevice();
                            for (String nic : nics) {
                                adapterMap.put(nic, vsConfig.getName());
                            }
                        }
                    }
                }
            }
            HostNetworkInfo networkInfo = hostNetworkSystem.getNetworkInfo();
            if (null != networkInfo) {
                // 分布式交换机上被用的物理网卡
                HostProxySwitch[] hostProxySwitchs = networkInfo.getProxySwitch();
                if (null != hostProxySwitchs && hostProxySwitchs.length > 0) {
                    for (HostProxySwitch hostProxySwitch : hostProxySwitchs) {
                        DistributedVirtualSwitchHostMemberPnicBacking dvsHostPnicBacking = (DistributedVirtualSwitchHostMemberPnicBacking) hostProxySwitch
                                .getSpec().getBacking();
                        DistributedVirtualSwitchHostMemberPnicSpec[] dvsHostPnics = dvsHostPnicBacking.getPnicSpec();
                        if (null != dvsHostPnics) {
                            for (DistributedVirtualSwitchHostMemberPnicSpec dvsHostPnic : dvsHostPnics) {
                                adapterMap.put(dvsHostPnic.getPnicDevice(), hostProxySwitch.getDvsName());
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 转换字段
     *
     * @param machine
     * @return
     * @throws Exception
     */
    public ServerModel convertServer(VirtualMachine machine) throws Exception {
        if (null == machine) {
            return null;
        }
        // 虚拟机配置信息
        VirtualMachineConfigInfo config = machine.getConfig();
        ServerModel serverModel = new ServerModel();
        ResourcePool resourcePool = machine.getResourcePool();
        if (null != resourcePool) {
            serverModel.setResPoolVal(resourcePool.getMOR().getVal());
        }
        if (null != machine.getSnapshot()) {
            VirtualMachineSnapshotTree[] snapshotArray = machine.getSnapshot().getRootSnapshotList();
            List<SnapshotModel> snapshotList = new ArrayList<>();
            // 获取虚拟机下的所有快照
            // 遍历取得的快照tree获取所有的快照
            snapshotList = traverseSnapshotTree(snapshotArray, snapshotList);
            serverModel.setSnapshots(snapshotList);
        }
        VirtualMachineSummary summary = machine.getSummary();
        serverModel.setInstanceId(summary.getConfig().getInstanceUuid());
        serverModel.setIsTemplate(summary.getConfig().isTemplate());
        // 内网IP
        GuestNicInfo[] guestNicInfos = machine.getGuest().getNet();
        if (null != guestNicInfos && guestNicInfos.length > 0) {
            List<Map<String, Object>> networks = new ArrayList<>();
            for (GuestNicInfo nicInfo : guestNicInfos) {
                Map<String, Object> network = new HashMap<>();
                network.put("networkName", nicInfo.getNetwork());
                if (null == nicInfo.getIpConfig() || null == nicInfo.getIpConfig().getIpAddress()) {
                    continue;
                }
                for (NetIpConfigInfoIpAddress address : nicInfo.getIpConfig().getIpAddress()) {
                    if (IpRangeUtil.ipV4Validate(address.getIpAddress())) {
                        network.put("address", address.getIpAddress());
                        network.put("prefix", address.getPrefixLength());
                    }
                }
                network.put("connected", nicInfo.connected);
                networks.add(network);
            }
            serverModel.setPrivateIps(JSONObject.toJSONString(networks));
        }
        GuestStackInfo[] stackInfos = machine.getGuest().getIpStack();
        if (null != stackInfos && stackInfos.length > 0) {
            String dns = null;
            String gateway = null;
            for (GuestStackInfo stackInfo : stackInfos) {
                String[] dnses = null;
                NetDnsConfigInfo netDnsConfigInfo = stackInfo.getDnsConfig();
                if (null != netDnsConfigInfo) {
                    dnses = netDnsConfigInfo.getIpAddress();
                }
                if (null != dnses) {
                    dns = dnses[0];
                }
                NetIpRouteConfigInfoIpRoute[] ipRoutes = null;
                NetIpRouteConfigInfo netIpRouteConfigInfo = stackInfo.getIpRouteConfig();
                if (null != netIpRouteConfigInfo) {
                    ipRoutes = netIpRouteConfigInfo.getIpRoute();
                }
                if (null != ipRoutes) {
                    for (NetIpRouteConfigInfoIpRoute ipRoute : ipRoutes) {
                        NetIpRouteConfigInfoGateway netIpRouteConfigInfoGateway = ipRoute.getGateway();
                        if (null != netIpRouteConfigInfoGateway) {
                            gateway = netIpRouteConfigInfoGateway.getIpAddress();
                        }
                        if (!StringUtils.isEmpty(gateway)) {
                            break;
                        }
                    }
                }
            }
            serverModel.setDns(dns);
            serverModel.setGateway(gateway);
        }
        serverModel.setManagerIp(summary.getGuest().getIpAddress());
        serverModel.setCpu(null == summary.getConfig().getNumCpu() ? 0 : summary.getConfig().getNumCpu());
        // summary.getConfig().getMemoryReservation()
        serverModel
                .setMemory(null == summary.getConfig().getMemorySizeMB() ? 0 : summary.getConfig().getMemorySizeMB());
        serverModel.setName(machine.getName());
        String status = BocloudStatus.Server.EXCEPTION.name();
        if (VirtualMachineConnectionState.inaccessible == summary.getRuntime().getConnectionState()) {
            status = BocloudStatus.Server.INACCESSIBLE.name();
        } else {
            status = summary.getRuntime().getPowerState().name();
        }
        serverModel.setStatus(status);
        serverModel.setUuid(summary.getConfig().getUuid());
        serverModel.setRemark(summary.getConfig().getAnnotation());
        GuestInfo guestInfo = machine.getGuest();
        String osCategory = null;
        if (null != guestInfo) {
            osCategory = guestInfo.getGuestFamily();
        }
        String fullName = null;
        if (StringUtils.isEmpty(osCategory)) {
            if (null != config) {
                osCategory = config.getGuestFullName();
            }
            if (StringUtils.isEmpty(osCategory)) {
                osCategory = OSCategory.Linux.name();
            } else if (osCategory.toLowerCase().contains(OSCategory.Windows.name().toLowerCase())) {
                osCategory = OSCategory.Windows.name();
            } else {
                osCategory = OSCategory.Linux.name();
            }
            VirtualMachineConfigInfo configInfo = machine.getConfig();
            if (null != configInfo) {
                fullName = configInfo.getGuestFullName();
            }
        } else {
            if (osCategory.toLowerCase().contains(OSCategory.Windows.name().toLowerCase())) {
                osCategory = OSCategory.Windows.name();
            } else {
                osCategory = OSCategory.Linux.name();
            }
            boolean isWindows = osCategory.contains("windowsGuest");
            serverModel.setAccount(isWindows ? "Administrator" : "root");
            if (null != guestInfo) {
                fullName = guestInfo.getGuestFullName();
            }
        }
        serverModel.setOsName(fullName);
        serverModel.setOsCategory(osCategory);
        VirtualMachineToolsStatus toolsStatus = summary.getGuest().getToolsStatus();
        if (null == toolsStatus) {
            serverModel.setToolsInstalled(false);
            serverModel.setToolsRunning(false);
        } else if ("toolsOk".equalsIgnoreCase(toolsStatus.toString())) {
            serverModel.setToolsInstalled(true);
            serverModel.setToolsRunning(true);
        } else if ("toolsNotInstalled".equalsIgnoreCase(toolsStatus.toString())) {
            serverModel.setToolsInstalled(false);
            serverModel.setToolsRunning(false);
        } else {
            serverModel.setToolsInstalled(true);
            serverModel.setToolsRunning(false);
        }
        Datastore[] datastores = machine.getDatastores();
        if (null != datastores && datastores.length > 0) {
            List<String> storeList = Lists.newArrayList();
            String stores = null;
            for (int i = 0; i < datastores.length; i++) {
                if (i == 0) {
                    stores = datastores[i].getName();
                } else {
                    stores += "," + datastores[i].getName();
                }
                storeList.add(datastores[i].getSummary().getDatastore().getVal());
            }
            serverModel.setStores(storeList);
            serverModel.setDatastores(stores);
        }
        Network[] networks = machine.getNetworks();
        List<NetworkModel> nets = Lists.newArrayList();
        if (null != networks && networks.length > 0) {
            for (Network network : networks) {
                NetworkModel model = new NetworkModel(network.getName(), null, network.getOverallStatus().name(), null,
                        network.getMOR().getVal());
                nets.add(model);
            }
        }
        serverModel.setNetworks(nets);
        if (null != config) {
            serverModel.setCpuHotEnable(config.getCpuHotAddEnabled());
            serverModel.setMemHotEnable(config.getMemoryHotAddEnabled());
            // 虚拟机系统磁盘
            long diskSize = 0;
            // 获取虚拟机下所有的物理网卡
            List<NetworkCardModel> networkModels = Lists.newArrayList();
            // 虚拟机关联设备
            VirtualDevice[] devices = config.getHardware().getDevice();
            List<VolumeModel> diskDevices = Lists.newArrayList();
            for (int i = 0; devices != null && i < devices.length; i++) {
                VirtualDevice device = devices[i];
                if (device instanceof VirtualDisk) {
                    // 封装磁盘设备元数据
                    VirtualDisk disk = (VirtualDisk) device;
                    diskDevices.add(assembleDiskDevice(disk, summary.getConfig().getUuid()));
                    diskSize += ((VirtualDisk) device).getCapacityInKB();
                }
                if (device instanceof VirtualEthernetCard) {
                    NetworkCardModel networkCardModel = new NetworkCardModel();
                    networkCardModel.setLabel(device.getDeviceInfo().getLabel());
                    networkCardModel.setMac(((VirtualEthernetCard) device).getMacAddress());
                    networkCardModel.setUsed(true);
                    String name = null;
                    VirtualDeviceBackingInfo backingInfo = device.getBacking();
                    // 判断网卡类型是标准交换机网络还是分布式交换机网络
                    
                    if (backingInfo instanceof VirtualDeviceDeviceBackingInfo) {
                        name = ((VirtualDeviceDeviceBackingInfo) backingInfo).getDeviceName();
                        networkCardModel.setPortType(NetworkType.PortGroupType.VIRTUAL.name());
                    } else if (backingInfo instanceof VirtualEthernetCardDistributedVirtualPortBackingInfo) {
                        // 查询分布式端口组名称
                        DistributedVirtualSwitchPortConnection portgroupConn = ((VirtualEthernetCardDistributedVirtualPortBackingInfo) backingInfo).getPort();
                        if (null != portgroupConn && !StringUtils.isEmpty(portgroupConn.getPortgroupKey())
                                && !StringUtils.isEmpty(portgroupConn.getSwitchUuid())) {
                            try {
                                DistributedVirtualSwitchManager switchManager = machine.getServerConnection()
                                        .getServiceInstance().getDistributedVirtualSwitchManager();
                                if (null != switchManager) {
                                    DistributedVirtualPortgroup dvPort = switchManager.dVSManagerLookupDvPortGroup(
                                            portgroupConn.getSwitchUuid(), portgroupConn.getPortgroupKey());
                                    if (null != dvPort) {
                                        name = dvPort.getName();
                                    }
                                }
                            } catch (Exception e2) {
                                logger.info("Get error message：", e2);
                            }
                        }
                        networkCardModel.setPortType(NetworkType.PortGroupType.DVPORT.name());
                    } else {
                        networkCardModel.setPortType(NetworkType.PortGroupType.UNKNOWN.name());
                    }
                    // 中泰项目修复【DistributedVirtualSwitchPortConnection portgroupConn = ((VirtualEthernetCardDistributedVirtualPortBackingInfo) (device
//                  .getBacking())).getPort()】bug，错误原因是类型转换异常，20190118
//                    if (backingInfo instanceof VirtualDeviceDeviceBackingInfo) {
//                        name = ((VirtualDeviceDeviceBackingInfo) device.getBacking()).getDeviceName();
//                        networkCardModel.setPortType(NetworkType.PortGroupType.VIRTUAL.name());
//                    } catch (Exception e) {
//                        // 查询分布式端口组名称
//                    	DistributedVirtualSwitchPortConnection portgroupConn = ((VirtualEthernetCardDistributedVirtualPortBackingInfo) backingInfo).getPort();
//                        DistributedVirtualSwitchPortConnection portgroupConn = ((VirtualEthernetCardDistributedVirtualPortBackingInfo) (device
//                                .getBacking())).getPort();
//                        if (null != portgroupConn && !StringUtils.isEmpty(portgroupConn.getPortgroupKey())
//                                && !StringUtils.isEmpty(portgroupConn.getSwitchUuid())) {
//                            try {
//                                DistributedVirtualSwitchManager switchManager = machine.getServerConnection()
//                                        .getServiceInstance().getDistributedVirtualSwitchManager();
//                                if (null != switchManager) {
//                                    DistributedVirtualPortgroup dvPort = switchManager.dVSManagerLookupDvPortGroup(
//                                            portgroupConn.getSwitchUuid(), portgroupConn.getPortgroupKey());
//                                    if (null != dvPort) {
//                                        name = dvPort.getName();
//                                    }
//                                }
//                            } catch (Exception e2) {
//                                logger.info("Get error message：", e2);
//                            }
//                        }
//                        networkCardModel.setPortType(NetworkType.PortGroupType.DVPORT.name());
//                    }
                    networkCardModel.setName(name);
                    networkModels.add(networkCardModel);
                }
            }
            serverModel.setDiskDevices(diskDevices);
            int disk = new BigDecimal(diskSize).divide(new BigDecimal(1024 * 1024L)).intValue();
            serverModel.setDisk(disk);
            serverModel.setNetcards(networkModels);
        } else {
            serverModel.setCpu(0);
            serverModel.setMemory(0);
            serverModel.setDisk(0);
            serverModel.setStatus("exception");
        }
        return serverModel;
    }

    /**
     * 封装磁盘设备元数据
     *
     * @param disk
     * @return
     */
    private VolumeModel assembleDiskDevice(VirtualDisk disk, String instanceId) {
        VolumeModel diskDeviceModel = new VolumeModel();
        Description deviceInfo = disk.getDeviceInfo();
        if (null != deviceInfo) {
            diskDeviceModel.setName(deviceInfo.getLabel());
        }
        BigDecimal bigDecimal = new BigDecimal(disk.getCapacityInKB()).divide(new BigDecimal(1024 * 1024L), 2,
                RoundingMode.HALF_UP);
        diskDeviceModel.setSize(bigDecimal.intValue());
        // diskDeviceModel.setDiskObjectId(disk.getDiskObjectId());
        return diskDeviceModel;
    }

    /**
     * 遍历从虚拟机获取的快照tree
     *
     * @param trees
     * @param snapshotList
     * @return
     */
    public List<SnapshotModel> traverseSnapshotTree(VirtualMachineSnapshotTree[] trees,
                                                    List<SnapshotModel> snapshotList) {
        if (null != trees) {
            for (VirtualMachineSnapshotTree tree : trees) {
                snapshotList.add(convert(tree));
                if (null != tree && null != tree.getChildSnapshotList()) {
                    traverseSnapshotTree(tree.getChildSnapshotList(), snapshotList);
                }
            }
        }
        return snapshotList;
    }

    /**
     * 把虚拟机获取的快照转换成自身想要的对象
     *
     * @param tree
     * @return
     */
    private SnapshotModel convert(VirtualMachineSnapshotTree tree) {
        SnapshotModel model = new SnapshotModel();
        if (null != tree) {
            // 快照创建时间
            model.setCreateTime(tree.getCreateTime().getTime());
            // 快照名称
            model.setName(tree.getName());
            // 快照ID
            model.setSnapshotUuid(tree.getId().toString());
            model.setSnapshotVal(tree.getSnapshot().getVal());
            // 快照状态
            if (tree.getState().equals(tree.state)) {
                model.setStatus("AVAILABLE");
            } else {
                model.setStatus("UNAVAILABLE");
            }
            model.setRemark(tree.getDescription());
        }
        return model;
    }
}
